package net.p2pcdn.pay.paypal;

import com.alibaba.fastjson.JSON;
import com.paypal.api.payments.*;
import com.paypal.base.rest.APIContext;
import com.paypal.base.rest.PayPalRESTException;
import net.p2pcdn.common.PayPalAccessTokenProvider;
import net.p2pcdn.core.order.domain.Order;
import net.p2pcdn.core.order.domain.PayType;
import net.p2pcdn.core.order.domain.PlatformEnum;
import net.p2pcdn.core.order.service.OrderService;
import net.p2pcdn.core.product.domain.Product;
import net.p2pcdn.core.product.domain.ProductType;
import net.p2pcdn.core.product.service.ProductService;
import net.p2pcdn.pay.OrderGenerator;
import net.p2pcdn.pay.OrderGeneratorFactory;
import net.p2pcdn.pay.paypal.config.CreatePaymentCommand;
import net.p2pcdn.pay.paypal.config.PaypalPaymentIntent;
import net.p2pcdn.pay.paypal.config.PaypalPaymentMethod;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class TrafficPackageGenerator implements OrderGenerator {
    @Resource
    private ProductService productService;
    @Autowired
    private PayPalAccessTokenProvider payPalAccessTokenProvider;
    @Autowired
    private OrderGeneratorFactory orderGeneratorFactory;
    @Autowired
    private OrderService orderService;
    @Autowired
    private APIContext apiContext;
    @Value("${paypal.mode}")
    private String mode;

    public APIContext getApiContext() {
        return apiContext;
    }

    @Override
    @Transactional(rollbackFor = {PayPalRESTException.class, RuntimeException.class})
    public Payment createPayment(CreatePaymentCommand command) throws PayPalRESTException {
        Amount amount = new Amount();
        Product product = productService.getProduct(command.getItemId());
        amount.setCurrency(command.getCurrency());
        amount.setTotal(String.format("%.2f", product.getPrice().multiply(new BigDecimal(command.getQuantity())).doubleValue()));
        Order addChargeOrder = orderService.createPackageOrder(command.getUserId(), command.getItemId(), command.getQuantity(), null, PayType.ONLINE, PlatformEnum.PAYPAL,command.getDomains());
        Transaction transaction = new Transaction();
        transaction.setDescription("P2PCDN-套餐购买,套餐名称：" + product.getName() + ",套餐ID:" + product.getSerial());
        transaction.setAmount(amount);
        transaction.setNotifyUrl(command.getNotifyUrl());
        transaction.setCustom(generatorCallbackParameterJSONString(command.getUserId(), command.getItemId(), command.getQuantity(), addChargeOrder.getTradeNo()));

        List<Transaction> transactions = new ArrayList<>();
        transactions.add(transaction);

        Payer payer = new Payer();
        payer.setPaymentMethod(command.getPaymentMethod().toString());

        Payment payment = new Payment();
        payment.setIntent(command.getPaypalPaymentIntent().toString());
        payment.setPayer(payer);
        payment.setTransactions(transactions);
        RedirectUrls redirectUrls = new RedirectUrls();
        redirectUrls.setCancelUrl(command.getCancelUrl()+"?tradeNo="+addChargeOrder.getTradeNo());
        redirectUrls.setReturnUrl(command.getSuccessUrl()+"?tradeNo="+addChargeOrder.getTradeNo());
        payment.setRedirectUrls(redirectUrls);
        Map<String, String> header = new HashMap<>();
        header.put("Authorization", "Basic " + payPalAccessTokenProvider.getAccessToken());
        APIContext context = new APIContext(getApiContext().getClientID(), getApiContext().getClientSecret(), mode);
        context.setHTTPHeaders(header);
        return payment.create(context);
    }

    @Override
    public ProductType getProductType() {
        return ProductType.PACKAGE;
    }

    public String generatorCallbackParameterJSONString(int userId, int itemId, int quantity, String orderNo) {
        Map<String, Object> params = new HashMap<>();
        params.put("buyer", userId);
        params.put("productType", getProductType().getValue());
        params.put("itemId", itemId);
        params.put("quantity", quantity);
        params.put("orderNo", orderNo);
        return JSON.toJSONString(params);
    }

    @Override
    public void afterPropertiesSet() {
        orderGeneratorFactory.addGenerator(getProductType(), this);
    }

}
